/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package TreeGenerator.Tools;

import com.jme3.bounding.BoundingBox;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Spatial;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.util.BufferUtils;
import com.jme3.util.Screenshots;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

/**
 *
 * @author Jannes
 */
public class RenderCrossSectionTexture implements SceneProcessor{
    private RenderManager renderManager;    
    private FrameBuffer offBuffer;        
    private ByteBuffer cpuBuf;
    private byte[] cpuArray;
    private BufferedImage image;
    private ViewPort offView;
    private Boolean imageDone,finalImageDone;
    private Spatial model;
    private BoundingBox bb;
    private Camera offCamera;
    private static Vector3f frontLocation = new Vector3f(0,0,-10);
    private static Vector3f backLocation = new Vector3f(0,0,10);
    private static Vector3f leftLocation = new Vector3f(-10,0,0);
    private static Vector3f rightLocation = new Vector3f(10,0,0);
    private Vector3f cameraLocation;
    private enum Location{
        FRONT,
        BACK,
        LEFT,
        RIGHT
    }
    
    public RenderCrossSectionTexture(float pixelsPerUnit, RenderManager renderManager, Spatial model_, BoundingBox modelBound){        
        int width = 256;
        int height = 256;
        cameraLocation = new Vector3f();
        bb = modelBound;
        model = model_.clone();
        this.renderManager = renderManager;
        cpuBuf = BufferUtils.createByteBuffer(width * height * 4);
        cpuArray = new byte[width * height * 4];
        image = new BufferedImage(width, height,BufferedImage.TYPE_4BYTE_ABGR);
        offCamera = new Camera(width, height);        
        // create a pre-view. a view that is rendered before the main view        
        offView = renderManager.createPreView("Offscreen View", offCamera);        
        
        offView.setBackgroundColor(ColorRGBA.Blue);
        offView.setClearFlags(true, true, true);
        
        // this will let us know when the scene has been rendered to the 
        // frame buffer
        //offView.addProcessor(this);        
        // create offscreen framebuffer
        offBuffer = new FrameBuffer(width, height, 1);

        //setup framebuffer's cam
        offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f);        
        //offCamera.setLocation(new Vector3f(0f, 0f, -100f));
        //offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);                        
        
        //setup framebuffer's texture
//        offTex = new Texture2D(width, height, Format.RGBA8);

        //setup framebuffer to use renderbuffer
        // this is faster for gpu -> cpu copies
        offBuffer.setDepthBuffer(Format.Depth);
        offBuffer.setColorBuffer(Format.RGBA8);
//        offBuffer.setColorTexture(offTex);
                
        //set viewport to render to offscreen framebuffer
        offView.setOutputFrameBuffer(offBuffer);
        model.updateGeometricState();
        offView.attachScene(model);
        createImage();
    }
    
    private void createImage(){
        finalImageDone = false;
        for(float cameraHeight = -16; cameraHeight < 16 ; cameraHeight += 2){
            RenderToTextureRotateCamera(renderManager, model, Location.FRONT, cameraHeight, bb);
            BufferedImage imagePart = getImageBlueBackGround();
            JOptionPane.showMessageDialog(null, new ImageIcon(image));
        }
        finalImageDone = true;
    }
    
    private void RenderToTextureRotateCamera(RenderManager renderManager, Spatial model_, Location location,float cameraHeight, BoundingBox modelBound){        
        imageDone = false;       
                
        if(location == Location.FRONT){
            bb.getCenter().add(frontLocation,cameraLocation);                        
        }else if(location == Location.BACK){
            bb.getCenter().add(backLocation,cameraLocation);
        }else if(location == Location.LEFT){
            bb.getCenter().add(leftLocation,cameraLocation);
        }else if(location == Location.RIGHT){
            bb.getCenter().add(rightLocation,cameraLocation);
        }
        cameraLocation = cameraLocation.add(0, cameraHeight, 0);
        offCamera.setLocation(cameraLocation);
        offCamera.lookAt(backLocation, Vector3f.UNIT_Y);
                        
        offView.addProcessor(this);        
    }
    
    public BufferedImage getImage(){
        
        while(!finalImageDone){
            try{
                Thread.sleep(10);
            }catch(Exception exc){}
        }
        renderManager.removePreView(offView);
        offView = null;        
        return Transparency.makeColorTransparent(image, Color.BLUE);
    }
    
    public BufferedImage getImageBlueBackGround(){
        while(!imageDone){
            try{
                Thread.sleep(10);
            }catch(Exception exc){}
        }        
        offView.removeProcessor(this);
        return image;
    }
    
    public void updateImageContents(){        
        cpuBuf.clear();
        renderManager.getRenderer().readFrameBuffer(offBuffer, cpuBuf);
        synchronized (image) {
            Screenshots.convertScreenShot(cpuBuf, image);                
        }
        offView.clearScenes();        
        imageDone = true;        
    }
    
    
    public void initialize(RenderManager rm, ViewPort vp) {}

    public void reshape(ViewPort vp, int w, int h) {}

    public boolean isInitialized() {
        return true;
    }

    public void preFrame(float tpf) {}

    public void postQueue(RenderQueue rq) {}

    public void postFrame(FrameBuffer out) {
        updateImageContents();
    }
    public void cleanup() {}
}
